{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "63e7595c",
   "metadata": {},
   "source": [
    "# Python语言特性：基础知识\n",
    "\n",
    "[廖雪峰Python课程](https://liaoxuefeng.com/books/python/web/index.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21b93446",
   "metadata": {},
   "source": [
    "## 1 Python的函数参数传递\n",
    "\n",
    "所有的变量都可以理解时内存中一个对象的引用，可以通过对变量赋值操作时，比较具体对象在内存中的地址id与变量所对应id的值，最终会发现它们两个是一致的。\n",
    "\n",
    "比较不同作用域下，同名变量实现对不同对象的引用.如下程序所示：在全局中定义一个变量a, 函数内部定义一个局部变量a, 分别对其赋值为1, 2. 比较其在内存中的位置，及其与内存对象的关系。\n",
    "\n",
    "类型术语对象， 而不是变量。而对象有两种，**可更改(mutable)**和**不可更改(immutable)**. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "551bca5a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "func-out: (140730124807072, {140730124807072})\n",
      "func_id: 140730124807072\n",
      "re-point: 140730124807104, 140730124807104\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "a = 1\n",
    "def func(a):\n",
    "    print(f\"func_id: {id(a)}\")\n",
    "    a = 2\n",
    "    print(f\"re-point: {id(a)}, {id(2)}\")\n",
    "print(f\"func-out: {id(a), {id(1)}}\")\n",
    "\n",
    "func(a)\n",
    "print(a) # 1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e22a83b",
   "metadata": {},
   "source": [
    "## 2 Python中的元类(metaclass)\n",
    "\n",
    "对于python中“一切都是对象，你怎么理解？”\n",
    "\n",
    "在python中，所有的内容都是一个对象，包括：整数、字符串、函数和类。它们都是对象，并且都是从元类创建或延伸而来的，这个类就是`type`,可以通过打印这些变量的“__class__”属性进行查看。\n",
    "\n",
    "元类只是创建类对象的东西，你可以称它为“class factory”，type是python内置的元类，当然用户也可以创建自己的元类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4016b008",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'>\n",
      "<class 'str'>\n",
      "<class 'function'>\n",
      "<class '__main__.Bar'>\n"
     ]
    }
   ],
   "source": [
    "age = 35\n",
    "print(age.__class__)\n",
    "# <type 'int'>\n",
    "name = 'bob'\n",
    "print(name.__class__)\n",
    "# <type 'str'>\n",
    "def foo(): pass\n",
    "print(foo.__class__)\n",
    "# <type 'function'>\n",
    "\n",
    "class Bar(object): pass\n",
    "b = Bar()\n",
    "print(b.__class__)\n",
    "    # <class '__main__.Bar'>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3eff52da",
   "metadata": {},
   "source": [
    "## 3 @staticmethod 和 @classmethod\n",
    "\n",
    "python有3个方法，即静态方法(staticmethod)，类方法(classmethod)和实例方法。它们之间的区别是什么？\n",
    "\n",
    "classmethod 和 实例方法区别体现在调用者和函数定义参数，前者需要显式地传入self代表类的实例，后者则应该传入cls代表类本身。\n",
    "\n",
    "类方法是一种方法，它作为第一个参数传递调用它的类或调用它的实例的类。当希望该方法称为类的工厂时，这非常有用：因为它获取调用它的类作为第一个参数，因此即使设计子类，我们也时钟可以实例化正确的类。\n",
    "\n",
    "staticmethod 是一种对调用它的类或实例一无所知的方法。它只获取传递的参数，没有隐含的第一个参数。实际上，它还让一个函数成为一个类变量。静态方法是编程时对代码进行组织并统一风格的重要方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "e90ccd79",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "executing foo (hello function) \n",
      "executing class_foo(<class '__main__.A'>, classmethod)\n",
      "executing class_foo(<class '__main__.A'>, A class method)\n",
      "executing static_foo(a static_foo function)\n",
      "executing static_foo(A class method)\n"
     ]
    }
   ],
   "source": [
    "def foo(x):\n",
    "    print(\"executing foo (%s) \" % x)\n",
    "\n",
    "class A(object):\n",
    "    def foo(self, x):\n",
    "        print(\"executing foo(%s, %s)\" % (self, x))\n",
    "\n",
    "    @classmethod\n",
    "    def class_foo(cls, x):\n",
    "        print(\"executing class_foo(%s, %s)\" % (cls, x))\n",
    "\n",
    "    @staticmethod\n",
    "    def static_foo(x):\n",
    "        print(\"executing static_foo(%s)\" % x)\n",
    "\n",
    "a = A()\n",
    "foo('hello function')\n",
    "\n",
    "a.class_foo('classmethod')  # 实例方法：传入类对象的实例\n",
    "A.class_foo('A class method')   # 类方法：传入类的抽象原型\n",
    "\n",
    "a.static_foo('a static_foo function')   # 定义在类的内部，无需传入隐形的与类有关的参数，但该方法在逻辑上属于该类\n",
    "A.static_foo('A class method')      # 既可以使用类的实例来调用该方法，也可以使用类本身调用该方法\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "babe84d4",
   "metadata": {},
   "source": [
    "## 4 类变量和实例变量\n",
    "\n",
    "类变量是在所有实例中共享的引用（它们本身并不是单独分配给每一个实例的）如下面所示：通过在定义一个类属性来追踪实例的调用。\n",
    "\n",
    "当类变量为可变对象时（字典，列表），共享类变量可能会造成意外的结果。因此，为了避免类变量的混淆，推荐使用self来定义实例变量，使用类名或cls来定义类变量。对于可变对象的类变量应该在定义中使用深复制来避免共享。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f3a3255b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "jack 2\n",
      "lucy 2\n"
     ]
    }
   ],
   "source": [
    "class Test(object):\n",
    "    call_static = 0\n",
    "    def __init__(self,name):\n",
    "        self.name = name\n",
    "        Test.call_static += 1\n",
    "\n",
    "# 实例化\n",
    "print(Test.call_static) # 0\n",
    "t1 = Test('jack')\n",
    "print(Test.call_static) # 1\n",
    "t2 = Test('lucy')\n",
    "print(Test.call_static) # 2\n",
    "\n",
    "print(t1.name, t1.call_static)\n",
    "print(t2.name, t2.call_static)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "572bef25",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1]\n",
      "[1]\n",
      "[1, 2]\n"
     ]
    }
   ],
   "source": [
    "class Person:\n",
    "    name = []\n",
    "\n",
    "p1 = Person()\n",
    "p2 = Person()\n",
    "\n",
    "p1.name.append(1)\n",
    "print(p1.name) # [1]\n",
    "print(p2.name)  # [1]\n",
    "\n",
    "p2.name.append(2)\n",
    "print(Person.name)  # [1, 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9401b0f6",
   "metadata": {},
   "source": [
    "## 5 Python 自省\n",
    "什么是python的自省？它的概念是什么？\n",
    "\n",
    "在python中，自省(Instrospection)指的是程序在运行过程中能够检查自身结构、属性和方法的能力，即程序可以动态地获取对象的信息，并以此调整自身的行为。\n",
    "\n",
    "为什么需要自省？\n",
    "因为在开发中经常会遇到需要处理“位未知对象”的场景，它们可能是在某个依赖模块中引入的。而，我们通过自省，可以在无需提前知道对象结构的情况下，动态地探究其细节，从而实现更加灵活，通用的代码。\n",
    "\n",
    "`type` - 返回对象的类型。\n",
    "`dir` - 返回对象的所有属性和方法的列表（字符串形式），包含内置属性（如 __init__）和自定义成员。\n",
    "`isinstance(object, class)` - 检查对象是否是某个类（或其父类）的实例，返回布尔值。\n",
    "`issubclass(class, classinfo)` - 检查一个类是否是另一个类的子类。\n",
    "`hasattr(object, name)` - 检查对象是否包含名为 name 的属性或方法（name 为字符串），返回布尔值。\n",
    "`getattr(object, name, default)` - 获取对象中名为 name 的属性或方法的值。如果不存在，返回 default（若未指定 default 则报错）。\n",
    "`__dict__` - 对象的 __dict__ 属性是一个字典，存储了对象的自定义属性（键为属性名，值为属性值）。类和实例都有此属性。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "556e593e",
   "metadata": {},
   "source": [
    "## 6 字典推导式\n",
    "\n",
    "字典推导式与列表推导式之间的区别\n",
    "\n",
    "     \n",
    "字典推导式和列表推导式都是 Python 里用于快速创建数据结构的语法糖，它们的主要区别如下：\n",
    "\n",
    "### 1. 返回对象类型\n",
    "- **列表推导式**：返回列表（`list`）对象，列表是有序的、可重复的元素集合，用方括号 `[]` 表示。\n",
    "- **字典推导式**：返回字典（`dict`）对象，字典是无序的键值对集合，用花括号 `{}` 表示，每个元素由键和值组成，键值之间用冒号 `:` 分隔。\n",
    "\n",
    "### 2. 语法结构\n",
    "- **列表推导式**：基本语法为 `[表达式 for 变量 in 可迭代对象 if 条件]`，重点在于生成单个元素组成的列表。\n",
    "- **字典推导式**：基本语法为 `{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}`，需要同时指定键和值的表达式。\n",
    "\n",
    "### 3. 元素唯一性\n",
    "- **列表推导式**：生成的列表可以包含重复元素。\n",
    "- **字典推导式**：字典的键具有唯一性，如果推导过程中出现重复键，后面的键值对会覆盖前面的。 \n",
    "        \n",
    "\n",
    "```python\n",
    "\n",
    "d = {key: value for (key, value) in iterable.items() }\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "2b2fbf86",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'jack', 'sex': 'man', 'age': 18, 'college': 'Beijing university'}\n"
     ]
    }
   ],
   "source": [
    "dic = {\"name\": \"jack\",\n",
    "       \"sex\": \"man\",\n",
    "       \"age\": 18,\n",
    "       \"college\": \"Beijing university\"}\n",
    "\n",
    "jack = {key: value for (key, value) in dic.items()}\n",
    "print(jack)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ec6d426",
   "metadata": {},
   "source": [
    "## 7 Python 中单下划线和双下划线\n",
    "\n",
    "无论是单下划线还是双下划线，它们都是一种约定\n",
    "\n",
    "__foo__: 其中双下划线式python内部的名字，用来区别其它用户自定义的命名，以防冲突。如__init__(), \\__del__(), \\__call__()\n",
    "\n",
    "_foo: 单下滑线是用来指定变量私有，不能用from muble import *导入，其它方面和公有访问机制相同；\n",
    "\n",
    "**__foo**: **解释器**用_classname__foo 来代替这个名字，以限制外部对它的随便访问，通过对象名._类名__xxx这样的方式来进行访问。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40b10081",
   "metadata": {},
   "source": [
    "## 8 字符串格式化：% 和 .format\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32d7b88f",
   "metadata": {},
   "source": [
    "## 9 迭代器和生成器\n",
    "\n",
    "**question**: 将列表生成式中[]改成之后()数据结构是否改变\n",
    "\n",
    "**answer**: \n",
    "会发生改变，它会从一个列表转变为一个生成器\n",
    "\n",
    "在什么情形下使用生成器？\n",
    "当我们需要访问大数据量时，如果使用列表作为容器，则会受到内存空间的限制，可以采用生成器的方式，一边循环，一边计算。\n",
    "          \n",
    "在 Python 中，将列表生成式的方括号 `[]` 替换为圆括号 `()` 后，数据结构会发生改变。使用方括号时，创建的是列表（`list`），列表是一种可迭代、可变且有序的数据结构，会一次性生成所有元素并存储在内存中。而使用圆括号创建的是生成器表达式（generator expression），生成器是一种特殊的迭代器，它不会一次性生成所有元素，而是按需惰性生成，节省内存空间。因此，替换括号会从创建列表变为创建生成器，数据结构和行为特性都有所不同。\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "45783829",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n",
      "<generator object <genexpr> at 0x0000023D42C53270>\n"
     ]
    }
   ],
   "source": [
    "L = [x*x for x in range(10)]\n",
    "print(L)\n",
    "\n",
    "g = (x*x for x in range(10))\n",
    "print(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f29f9d0",
   "metadata": {},
   "source": [
    "## 10 *args and **kwargs\n",
    "\n",
    "当不确定函数传递参数的数量时，可以使用*args。\n",
    "\n",
    "而**kwargs允许使用没有事先定义的参数名，它以键值对的方式传入参数。\n",
    "\n",
    "如果想要混合使用*args 和 \\*\\*kwargs，*args必须在**kwargs前面"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "e503a937",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: hello\n",
      "1: my\n",
      "2: favorite\n",
      "3: fruit\n",
      "4: is\n",
      "5: apple\n"
     ]
    }
   ],
   "source": [
    "def arg_demo(*args):\n",
    "    for id, content in enumerate(args):\n",
    "        print(f'{id}: {content}')\n",
    "\n",
    "arg_demo('hello', 'my', 'favorite', 'fruit', 'is', 'apple')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "4af65a6b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apple-fruit\n",
      "cabbage-vegetable\n"
     ]
    }
   ],
   "source": [
    "def kwargs_demo(**kwargs):\n",
    "    for name, value in kwargs.items():\n",
    "        print(f'{name}-{value}')\n",
    "\n",
    "kwargs_demo(apple = 'fruit', cabbage = 'vegetable')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b23a6660",
   "metadata": {},
   "source": [
    "## 11 面向切面编程AOP和装饰器\n",
    "\n",
    "装饰器的作用是为已经存在的对象添加额外的功能。\n",
    "\n",
    "它常用在有切面需求的场景中，例如：插入日志、性能测试、事务处理等。\n",
    "\n",
    "其特点在于：可以帮助用户抽离出大量的函数中与其功能无关的代码实现重用。\n",
    "\n",
    "函数是一个对象，因此你可以看到它能够被赋给一个变量，同时他还能能够在一个函数中进行定义。这意味着一个函数可以返回另一个函数。\n",
    "\n",
    "[How do I make function decorators and chain them together?](https://stackoverflow.com/questions/739654/how-do-i-make-function-decorators-and-chain-them-together)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "e5b3eeca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<function getTalk.<locals>.shout at 0x0000023D42D37550>\n",
      "Yes!\n",
      "yes...\n"
     ]
    }
   ],
   "source": [
    "def getTalk(kind=\"shout\"):\n",
    "\n",
    "    # We define functions on the fly\n",
    "    def shout(word=\"yes\"):\n",
    "        return word.capitalize()+\"!\"\n",
    "\n",
    "    def whisper(word=\"yes\") :\n",
    "        return word.lower()+\"...\"\n",
    "\n",
    "    # Then we return one of them\n",
    "    if kind == \"shout\":\n",
    "        # We don't use \"()\", we are not calling the function,\n",
    "        # we are returning the function object\n",
    "        return shout  \n",
    "    else:\n",
    "        return whisper\n",
    "\n",
    "# How do you use this strange beast?\n",
    "\n",
    "# Get the function and assign it to a variable\n",
    "talk = getTalk()      \n",
    "\n",
    "# You can see that \"talk\" is here a function object:\n",
    "print(talk)\n",
    "#outputs : <function shout at 0xb7ea817c>\n",
    "\n",
    "# The object is the one returned by the function:\n",
    "print(talk())\n",
    "#outputs : Yes!\n",
    "\n",
    "# And you can even use it directly if you feel wild:\n",
    "print(getTalk(\"whisper\")())\n",
    "#outputs : yes..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94093b9b",
   "metadata": {},
   "source": [
    "## 12 鸭子类型\n",
    "\n",
    "“当一只鸟走起来像鸭子，游泳像鸭子，叫起来也像鸭子，那么这只鸟就可以被称为鸭子。”\n",
    "\n",
    "也就是用户并不关心对象是什么类型，它到底是不是鸭子，只关心它的行为。\n",
    "\n",
    "**例如**：\n",
    "python中，很多file-like的内容，比如：StringIO, GzipFile, Socket. 它们有很多相同的方法，我们可以将其当作文件使用。\n",
    "\n",
    "另外还有extend()方法中，我们不关心它的参数是不是list，只要它是可迭代的，那么它的参数就可以是：list, tuple, dict"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fecdb8ee",
   "metadata": {},
   "source": [
    "## 13 Python中的重载\n",
    "重载的两种类型：\n",
    "1. 可变参数类型\n",
    "2. 可变参数个数\n",
    "\n",
    "什么情况下使用这个模式？\n",
    "\n",
    "设计规则：对于一个函数，它的功能不变，但是输入参数改变（包括：**参数类型，参数个数**），这时可以使用函数重载。如果两个函数的功能不尽相同，则应当重新定义一个函数。\n",
    "\n",
    "在 Python 中，重载（Overloading） 通常指两种不同的概念：方法重载（Method Overloading） 和 运算符重载（Operator Overloading）。这两种机制都允许函数或运算符根据不同的参数类型或数量表现出不同的行为，但实现方式和应用场景有所区别。\n",
    "\n",
    "Python 不直接支持传统的方法重载（即无法通过定义多个同名方法来实现），因为 Python 是动态类型语言，方法签名（参数类型和数量）在运行时才确定。\n",
    "\n",
    "**运算符重载概念**：通过定义特殊方法（如 __add__, __sub__ 等），让自定义类的对象支持内置运算符（如 +, -, * 等）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "3cef9775",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25\n",
      "50\n"
     ]
    }
   ],
   "source": [
    "class Shape:\n",
    "    def area(self, x=None, y=None):\n",
    "        if x is not None and y is not None:\n",
    "            return x * y  # 矩形面积\n",
    "        elif x is not None:\n",
    "            return x ** 2  # 正方形面积\n",
    "        else:\n",
    "            return 0  # 默认返回 0\n",
    "\n",
    "s = Shape()\n",
    "print(s.area(5))       # 输出 25（正方形）\n",
    "print(s.area(5, 10))   # 输出 50（矩形）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "9a0f98ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 6)\n",
      "(-2, -2)\n"
     ]
    }
   ],
   "source": [
    "class Vector:\n",
    "    def __init__(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "\n",
    "    def __add__(self, other):\n",
    "        return Vector(self.x + other.x, self.y + other.y)\n",
    "\n",
    "    def __sub__(self, other):\n",
    "        return Vector(self.x - other.x, self.y - other.y)\n",
    "\n",
    "    def __str__(self):\n",
    "        return f\"({self.x}, {self.y})\"\n",
    "\n",
    "v1 = Vector(1, 2)\n",
    "v2 = Vector(3, 4)\n",
    "print(v1 + v2)  # 输出: (4, 6)\n",
    "print(v1 - v2)  # 输出: (-2, -2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "745f94ee",
   "metadata": {},
   "source": [
    "## 14 新式类和旧式类\n",
    "\n",
    "类和实例有两种风格：old-style（或 classic）和 new-style。\n",
    "\n",
    "引入 new-style 类的主要动机是提供具有完整元模型的统一对象模型。它还具有许多实际的好处，例如能够对大多数内置类型进行子类化，或者引入启用计算属性的“描述符”。\n",
    "\n",
    "在新的对象模型中，继承方式和经典对象模型大体相同，一个关键的区别就是新式类能够从python的内置类型中继承，而经典类不行。\n",
    "\n",
    "旧式类是在类继承搜索类方法过程中使用的是深度优先的算法，如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "2b94a5aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C\n"
     ]
    }
   ],
   "source": [
    "class A():\n",
    "    def foo1(self):\n",
    "        print(\"A\")\n",
    "class B(A):\n",
    "    def foo2(self):\n",
    "        pass\n",
    "class C(A):\n",
    "    def foo1(self):\n",
    "        print(\"C\")\n",
    "class D(B, C):\n",
    "    pass\n",
    "d = D()\n",
    "d.foo1() # 新式类会输出C，而旧式类会输出A"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0e9803d",
   "metadata": {},
   "source": [
    "经典类（旧式类）遵循`从左到右深度优先`的规则，在访问d.fool()时，会先往上查找，找到B，没有在里面找到，深度优先访问了A，找到foo1(), 因此这时候调用的是A的foo1()，从而导致C类中重写的foo1函数被绕过。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbf28214",
   "metadata": {},
   "source": [
    "## 15 __new__ 和 __init__的区别\n",
    "\n",
    "1. \\__new__ 是一个静态方法，而\\__init__是一个实例方法\n",
    "2. \\__new__方法会返回一个创建的实例，而\\__init__什么都不会返回\n",
    "3. 只有在\\__new__返回一个cls的实例时，后面的\\__init__才被调用\n",
    "4. 当创建一个实例时调用\\__new__，初始化一个实例时调用\\__init__\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d177c3ca",
   "metadata": {},
   "source": [
    "## 16 什么是**工厂设计模式**\n",
    "\n",
    "这里的 “Factory” 指工厂模式（Factory Pattern），一种常见的创建型设计模式。它的核心思想是：将对象的创建逻辑封装在专门的 “工厂” 类或函数中，而不是直接在代码中用 new（或 Python 中的 ClassName()）硬编码对象创建过程。\n",
    "\n",
    "当需要根据不同条件创建不同类型的对象（例如，根据参数返回 Circle 或 Rectangle 实例）时，工厂模式是行业公认的最佳实践 —— 它能隐藏复杂的创建逻辑，让调用者通过统一的接口获取对象，提高代码的可维护性和扩展性。\n",
    "\n",
    "**工厂模式的核心作用**\n",
    "1. 解耦对象的创建和使用\n",
    "2. 同一对象的创建逻辑\n",
    "3. 符合设计原则\n",
    "\n",
    "**场景设计**：\n",
    "1. 对象创建过程复杂，或者需要隐藏实现细节\n",
    "2. 根据条件动态创建对象\n",
    "3. 框架开发，需要提供通用的扩展点"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f556dfec",
   "metadata": {},
   "source": [
    "## 17 单例模式\n",
    "\n",
    "**这个绝对常考啊.一定要记住1~2个方法，当时面试官是让手写的**\n",
    "\n",
    "单例模式是一种常见的软件设计模式。它的核心结构中只包含一个被称为单例类的特殊类，借此可以保证系统中只有一个类的实例，便于外界访问，从而实现对实例个数的控制并节约资源。\n",
    "\n",
    "\\__new__ 是 Python 中创建实例的 “构造器”（在 \\__init__ 之前执行），负责返回一个类的新实例。重写 \\__new__ 可以控制实例的创建过程。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "169c763a",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 1、使用__new__方法\n",
    "\n",
    "class Singleton(object):\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        if not hasattr(cls, '_instance'): # 判断是否已经创建过该类的实例\n",
    "            orig = super(Singleton, cls) # 返回父类的代理 -> 即object, cls则指定当前类的上下文\n",
    "            cls._instance = orig.__new__(cls, *args, **kwargs)\n",
    "        return cls._instance    # 返回唯一的实例\n",
    "\n",
    "class MyClass(Singleton):\n",
    "    a = 1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "68883155",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 2、共享属性: 多实例而状态统一\n",
    "# 创建实例时，把所有实例的__dict__指向同一个字典，这样它们具有相同的属性和方法\n",
    "\n",
    "class Borg(object):\n",
    "    _state = {}\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        ob = super(Borg, cls).__new__(cls, *args, **kwargs)\n",
    "        ob.__dict__ = cls._state\n",
    "        return ob\n",
    "    \n",
    "class MyClass2(Borg):\n",
    "    a = 1\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb941373",
   "metadata": {},
   "source": [
    "这段 Python 代码实现了 Borg 模式（也称为 Monostate 模式），核心特点是让类的所有实例共享 同一个状态（属性字典），但实例本身是独立的对象。与 “单例模式（确保唯一实例）” 不同，Borg 模式允许创建多个实例，但它们的属性会相互影响（因为共享同一个状态字典）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "48c234e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 3 装饰器版本\n",
    "\n",
    "def singleton(cls):\n",
    "    instances = {}\n",
    "    def getinstance(*args, **kwargs):\n",
    "        if cls not in instances:\n",
    "            instances[cls] = cls(*args, **kwargs)\n",
    "        return instances\n",
    "    return getinstance\n",
    "\n",
    "@singleton\n",
    "class Myclass:\n",
    "    ... "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "46874066",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 4 import 方法\n",
    "\n",
    "# mysingleton.py\n",
    "\n",
    "class My_Singleton(object):\n",
    "    def foo(self):\n",
    "        pass\n",
    "\n",
    "my_singleton = My_Singleton()\n",
    "\n",
    "## use in the file\n",
    "\n",
    "# from mysingleton import My_Singleton\n",
    "\n",
    "# my_singleton.foo()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42dce252",
   "metadata": {},
   "source": [
    "## 18 Python中的作用域\n",
    "\n",
    "在python中，一个变量的作用域总是由在代码中被赋值的地方所决定。\n",
    "\n",
    "当python解释器在处理变量的时候，会按照如下方式进行搜索：\n",
    "    1. 本地作用域（Local）\n",
    "    2. 当前作用域被嵌入的本地作用域（Enclosing local Global）\n",
    "    3. 内置的作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3c6bdcb",
   "metadata": {},
   "source": [
    "## 19 GIL线程全局锁\n",
    "\n",
    "[什么是Python全局锁(GIL),如何避开它的限制](https://zhuanlan.zhihu.com/p/639387706)\n",
    "\n",
    "**GIL**: Global Interpreter Lock \n",
    "Python为了保证线程安全而采取的独立线程运行的机制，也就是说python解释器在同一时间只能运行一个线程。对于I/O密集型人物，可以使用Python的多线程运行机制，但是对于CPU密集型任务，即便使用多线程，它的性能提升也微乎其微，还有可能因为争夺资源而变慢。\n",
    "\n",
    "解决方法：可以使用多进程和协程\n",
    "\n",
    "          \n",
    "用户需要了解进程、Python 中进程、多进程协程以及线程之间的关系，调用 web_search 工具获取相关知识。\n",
    "                \n",
    "query: 进程、Python 中进程、多进程协程以及线程之间的关系\n",
    "          \n",
    "以下为您解释进程、Python 中进程、多进程、协程以及线程之间的关系：\n",
    "\n",
    "### 基本概念\n",
    "1. **进程**：一个程序运行起来后，代码和用到的资源的总和称为进程，它是操作系统分配资源的基本单元。每个进程都有自己独立的内存空间，不同进程间的内存空间不能共享，子进程执行前会复制一份主进程的代码（不包括进程 ID 等）<mcreference link=\"https://blog.csdn.net/Terminator_wh/article/details/84565103\" index=\"1\">1</mcreference>。\n",
    "2. **线程**：操作系统中能够进行运算调度的最小单位，被包含在进程之中，是进程中的实际运作单位。一个进程至少有一个线程<mcreference link=\"https://blog.csdn.net/Terminator_wh/article/details/84565103\" index=\"1\">1</mcreference>。\n",
    "3. **协程**：又称为微线程，是一种用户态的轻量级线程。协程的上下文切换由用户自己决定，切换任务时资源消耗小，效率高<mcreference link=\"https://blog.csdn.net/java_huizhen/article/details/122582539\" index=\"4\">4</mcreference>。\n",
    "\n",
    "### 相互关系\n",
    "1. **进程与线程**：一个线程只能属于一个进程，而一个进程可以有多个线程。资源分配给进程，同一进程中的所有线程共享该进程的所有资源<mcreference link=\"https://blog.csdn.net/Terminator_wh/article/details/84565103\" index=\"1\">1</mcreference>。\n",
    "2. **线程与协程**：一个线程可以包含多个协程。线程和进程是同步机制，而协程是异步的<mcreference link=\"https://blog.csdn.net/java_huizhen/article/details/122582539\" index=\"4\">4</mcreference>。\n",
    "3. **多进程与协程**：多进程表示程序可同时执行多个任务，进程由操作系统调度完成。在 Python 里可结合多进程和协程，利用多进程突破全局解释器锁（GIL）的限制，再在进程内使用协程提高并发效率。\n",
    "\n",
    "### Python 中的特殊情况\n",
    "在 Python 中，由于存在全局解释器锁（GIL），同一时刻只能有一个线程在运行，这使得 Python 的多线程无法充分利用多核 CPU 资源。因此在 CPU 密集型任务中，多进程比多线程更有优势；而在 I/O 密集型任务中，协程和多线程都能提升程序性能<mcreference link=\"https://blog.csdn.net/weixin_39506322/article/details/101052872\" index=\"2\">2</mcreference><mcreference link=\"https://blog.csdn.net/weixin_50071922/article/details/129799558\" index=\"5\">5</mcreference>。 \n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b185dde",
   "metadata": {},
   "source": [
    "## 20 协程\n",
    "\n",
    "协程，又称微线程，英文名：Coroutine\n",
    "\n",
    "**协程与线程**\n",
    "子程序的调用是通过栈实现的，一个线程就是执行一个子程序。\n",
    "\n",
    "子程序调用总是一个入口，一次返回，它的调用顺序明确。而协程的调用和子程序不同。\n",
    "\n",
    "协程看上去也是子程序，但是执行过程中，在子程序内部可以中断，转而执行其它的子程序，并在适当的时候可以返回来再接着执行。\n",
    "\n",
    "**它的优势在于**：\n",
    "1. 无需为任务的切换耗费额外的时间成本，性能优势明显\n",
    "2. 不需要多线程的锁机制，因为只有一个线程，在资源控制方面，无需加锁，只用判断状态即可。\n",
    "\n",
    "\n",
    "- 协程是一个线程执行，那么如何利用多核CPU？可以通过多线程和协程组合实现对应的方案。\n",
    "\n",
    "- python对协程的支持是通过generator实现的。\n",
    "\n",
    "- Donald Knuth总结的特点：“子程序是协程的一种特例。”\n",
    "\n",
    "\n",
    "[参考:廖雪峰的python教程](https://liaoxuefeng.com/books/python/async-io/coroutine/index.html)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "7abcf462",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[PRODUCER] Producing 1...\n",
      "[CONSUMER] Consuming 1...\n",
      "[PRODUCER] Consumer return: 200 OK\n",
      "[PRODUCER] Producing 2...\n",
      "[CONSUMER] Consuming 2...\n",
      "[PRODUCER] Consumer return: 200 OK\n",
      "[PRODUCER] Producing 3...\n",
      "[CONSUMER] Consuming 3...\n",
      "[PRODUCER] Consumer return: 200 OK\n",
      "[PRODUCER] Producing 4...\n",
      "[CONSUMER] Consuming 4...\n",
      "[PRODUCER] Consumer return: 200 OK\n",
      "[PRODUCER] Producing 5...\n",
      "[CONSUMER] Consuming 5...\n",
      "[PRODUCER] Consumer return: 200 OK\n"
     ]
    }
   ],
   "source": [
    "## 生产者消费者模型\n",
    "\n",
    "def consumer():\n",
    "    r = ''\n",
    "    while True:\n",
    "        n = yield r\n",
    "        if not n:\n",
    "            return \n",
    "        print('[CONSUMER] Consuming %s...' % n)\n",
    "        r = '200 OK'\n",
    "\n",
    "def produce(c):\n",
    "    c.send(None)\n",
    "    n = 0\n",
    "    while n < 5:\n",
    "        n += 1\n",
    "        print('[PRODUCER] Producing %s...' % n)\n",
    "        r = c.send(n)\n",
    "        print('[PRODUCER] Consumer return: %s' % r)\n",
    "    c.close()\n",
    "\n",
    "c = consumer()\n",
    "produce(c)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dac9f5a6",
   "metadata": {},
   "source": [
    "consumer函数是一个generator（生成器）,整个过程无锁，由一个线程执行，produce 和 consumer 协作完成任务。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dfbf5ab",
   "metadata": {},
   "source": [
    "## 20 闭包\n",
    "\n",
    "闭包是一种组织代码的方式，可以增强代码的复用性。\n",
    "\n",
    "1. 必须有⼀个内嵌函数\n",
    "2. 内嵌函数必须引用外部函数中的变量\n",
    "3. 外部函数的返回值必须是内嵌函数\n",
    "\n",
    "有两种常见的应用场景：\n",
    "1. 函数工厂\n",
    "2. 回调函数\n",
    "\n",
    "[Python闭包:深入理解与高效使用](https://geek-blogs.com/blog/python-closure/)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "          \n",
    "用户需要了解 Python 中闭包的概念、功能和特点，调用 web_search 工具获取相关知识。\n",
    "        \n",
    "            \n",
    "toolName: web_search\n",
    "            \n",
    "status: success\n",
    "          \n",
    "query: Python 中闭包的概念、功能和特点\n",
    "          \n",
    "在 Python 里，闭包是一个重要的概念，以下为你介绍闭包的概念、功能和特点：\n",
    "\n",
    "### 闭包的概念\n",
    "闭包是一个函数，以及该函数的词法环境（lexical environment）的引用。这个环境包含了该函数定义时的任何局部变量。简单来说，闭包允许在内层函数中访问其外层函数的作用域，即使外层函数执行结束，内层函数依然能访问这些变量<mcreference link=\"https://blog.csdn.net/m0_49243785/article/details/140344117\" index=\"1\">1</mcreference>。\n",
    "\n",
    "### 闭包的组成部分\n",
    "闭包由两部分构成<mcreference link=\"https://blog.csdn.net/m0_49243785/article/details/140344117\" index=\"1\">1</mcreference>：\n",
    "1. **函数**：闭包的代码部分，包含函数的声明。\n",
    "2. **词法环境**：闭包的环境部分，包含函数定义时的环境。\n",
    "\n",
    "### 闭包的形成条件\n",
    "要形成闭包，必须满足以下三个条件<mcreference link=\"https://www.cnblogs.com/Fennix/p/18972392\" index=\"2\">2</mcreference>：\n",
    "1. 存在一个嵌套函数（即在函数内部定义另一个函数）。\n",
    "2. 嵌套函数引用了外部函数的变量。\n",
    "3. 外部函数返回了嵌套函数。\n",
    "\n",
    "### 代码示例\n",
    "```python\n",
    "# 示例 1\n",
    "def outer_function(x):\n",
    "    def inner_function(y):\n",
    "        return x + y\n",
    "    return inner_function\n",
    "\n",
    "closure_example = outer_function(10)\n",
    "print(closure_example(5))  # 输出: 15\n",
    "\n",
    "# 示例 2\n",
    "def make_multiplier_of(n):\n",
    "    def multiplier(x):\n",
    "        return x * n\n",
    "    return multiplier\n",
    "\n",
    "times_three = make_multiplier_of(3)\n",
    "times_five = make_multiplier_of(5)\n",
    "print(times_three(9))  # 输出: 27\n",
    "print(times_five(3))  # 输出: 15\n",
    "```\n",
    "\n",
    "### 闭包的功能\n",
    "1. **数据封装**：可以将数据和操作封装在一起，类似于对象的私有属性，使得这些变量不被外部直接访问，只通过特定的接口暴露功能<mcreference link=\"https://www.cnblogs.com/Fennix/p/18972392\" index=\"2\">2</mcreference>。\n",
    "2. **延迟计算**：保存状态，延迟执行，直到闭包被调用时才执行相应的操作<mcreference link=\"https://www.cnblogs.com/Fennix/p/18972392\" index=\"2\">2</mcreference>。\n",
    "3. **避免全局变量**：减少全局变量的使用，避免命名冲突<mcreference link=\"https://www.cnblogs.com/Fennix/p/18972392\" index=\"2\">2</mcreference>。\n",
    "4. **实现装饰器**：装饰器本质上就是闭包的应用，可用于扩展函数的功能<mcreference link=\"https://www.cnblogs.com/Fennix/p/18972392\" index=\"2\">2</mcreference>。\n",
    "\n",
    "### 闭包的特点<mcreference link=\"https://blog.csdn.net/m0_49243785/article/details/140344117\" index=\"1\">1</mcreference>：\n",
    "1. **记忆性**：闭包能够“记住”并访问其创建时的词法环境，即使外部函数已经执行结束。\n",
    "2. **封装性**：可以封装私有变量，提高代码的安全性和可维护性。\n",
    "3. **延迟执行**：闭包可以在创建后延迟执行，直到被调用时才进行计算。 \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "c5595cc5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15\n",
      "==========\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "## 简单示例\n",
    "\n",
    "def outer_func(x):\n",
    "    def inner_func(y):\n",
    "        return x + y\n",
    "    return inner_func\n",
    "\n",
    "closure = outer_func(10)\n",
    "\n",
    "result = closure(5)\n",
    "print(result)\n",
    "print(\"==========\")\n",
    "\n",
    "def outer_function():\n",
    "    count = 0\n",
    "    def inner_function():\n",
    "        nonlocal count\n",
    "        count += 1\n",
    "        return count\n",
    "    return inner_function\n",
    "\n",
    "closure = outer_function()\n",
    "\n",
    "print(closure())\n",
    "print(closure())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "34c24b46",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25\n",
      "125\n"
     ]
    }
   ],
   "source": [
    "## 函数工厂\n",
    "\"\"\"闭包可以用于创建函数工厂，即使根据不同的参数生成不同的函数。\"\"\"\n",
    "\n",
    "def power_function(n):\n",
    "    def inner_function(x):\n",
    "        return x**n\n",
    "    return inner_function\n",
    "\n",
    "# 创建平方函数\n",
    "square = power_function(2)\n",
    "# 创建立方函数\n",
    "cube = power_function(3)\n",
    "\n",
    "print(square(5))    # 输出：25\n",
    "print(cube(5))      #输出：125"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "681bed20",
   "metadata": {},
   "source": [
    "在这个例子中，power_function 是一个函数工厂，它根据传入的参数 n 生成不同的幂函数。调用 power_function(2) 生成一个平方函数，调用 power_function(3) 生成一个立方函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "124faca8",
   "metadata": {},
   "source": [
    "## 22 lambda函数\n",
    "\n",
    "[匿名函数](https://liaoxuefeng.com/books/python/functional/lambda/index.html)\n",
    "\n",
    "在某些场景中：当我们想要使用一个能够实现简单功能的函数，但是对它的使用频率较低。此时，我们不需要显式地定义函数，直接传入匿名函数更方便。\n",
    "\n",
    "匿名函数有一个限制：\n",
    "    只能有一个表达式，无需写return，返回值就是表达式的结果\n",
    "    python对匿名函数的支持有限，在相对简单的情况下才能发挥出它的优势。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "a6602844",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 64, 2187, 65536]"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 计算幂次方\n",
    "list(map(lambda x, n: x**n, [1,2,3,4],[5,6,7,8]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "f7650410",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True]\n"
     ]
    }
   ],
   "source": [
    "## 判断是否为奇数\n",
    "\n",
    "L = list(map(lambda x: x % 2 == 1, range(1,20)))\n",
    "print(L)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "483cf166",
   "metadata": {},
   "source": [
    "## 23 python函数式编程\n",
    "\n",
    "- filter\n",
    "- map\n",
    "- reduce\n",
    "\n",
    "`map` 和 `filter` 是内置函数，在python解释器启动时就已经可以直接使用，而 `reduce`函数在python3中被移动到了functools模块中。\n",
    "\n",
    "**为什么要将reduce移动到functools中？**\n",
    "\n",
    "主要是因为该工具在编程实践中使用频率较低，为了减少内置命名空间污染，因而将其移动至functools中。\n",
    "\n",
    "[酷壳：python函数式编程](https://coolshell-mirror.work.zhuzhilong.com/articles/10822.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "8ea12033",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<filter object at 0x0000023D43F6D0A0>\n",
      "<class 'filter'>\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "## filter函数\n",
    "\"\"\"过滤器：调用一个布尔函数bool_func 迭代遍历返回值为True的元素序列\"\"\"\n",
    "\n",
    "a = [1, 2, 3, 4, 5, 6]\n",
    "b = filter(lambda x: x > 2, a)\n",
    "print(b)    # <filter object at 0x000001B1363D2B20>\n",
    "print(type(b))\n",
    "\n",
    "for i in b:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "ec1f071d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'map'>\n",
      "<map object at 0x0000023D43F6D340>\n",
      "2\n",
      "4\n",
      "6\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "## map 函数\n",
    "\"\"\" 对序列的每一个元素依次执行map映射的自定义函数 \"\"\"\n",
    "a = map(lambda x: x * 2, [1, 2, 3, 4])\n",
    "print(type(a))\n",
    "print(a)\n",
    "\n",
    "for i in a:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "75e8f4dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15\n"
     ]
    }
   ],
   "source": [
    "## reduce 函数\n",
    "\"\"\" 将序列依次迭代的元素传入自定义的函数中，并返回最终运算得到的值 \"\"\"\n",
    "\n",
    "from functools import reduce\n",
    "\n",
    "a = reduce(lambda x, y: x + y, [1,2,3,4,5])\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d937def",
   "metadata": {},
   "source": [
    "## 24 python中的拷贝\n",
    "\n",
    "**question**:\n",
    "\n",
    "“引用” 和 `copy()` 、`deepcopy()`的区别是什么？\n",
    "\n",
    "对于可变对象和不可变对象，它们有不同的特性：\n",
    "- 不可变对象，一旦创建就不允许修改。\n",
    "- 可变对象：\n",
    "- 浅拷贝和深拷贝，它们在应用于“复合对象”时，有较大的区别。\n",
    "\n",
    "赋值语句创建复合对象副本时，python并没有克隆对象本身。相反，它只是将引用绑定到目标对象上，可以通过`id`来进行查看。也就是说，当我们使用赋值语句对变量进行赋值时，实际上我们构建了两个引用变量，它们指向内存中同一个对象。\n",
    "\n",
    "浅拷贝：创建一个新的对象，其内容是原始对象的引用\n",
    "浅拷贝构建一个复合对象，然后将原符合对象包含的对象插入到新的复合对象中。\n",
    "\n",
    "\n",
    "\n",
    "[参考知乎：python中的拷贝](https://www.zhihu.com/question/326220443)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "91d2d618",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原始列表: a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]\n",
      "引用: b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]\n",
      "浅拷贝: c =  [1, 2, 3, 4, ['a', 'b', 'c']]\n",
      "深拷贝: d =  [1, 2, 3, 4, ['a', 'b']]\n"
     ]
    }
   ],
   "source": [
    "import copy\n",
    "\n",
    "a = [1, 2, 3, 4, ['a', 'b']]\n",
    "\n",
    "b = a   # 引用\n",
    "c = copy.copy(a)    # 浅拷贝\n",
    "d = copy.deepcopy(a)    # 深拷贝\n",
    "\n",
    "a.append(5)\n",
    "a[4].append('c')\n",
    "\n",
    "print('原始列表: a = ', a)\n",
    "print('引用: b = ', b)\n",
    "print('浅拷贝: c = ', c)\n",
    "print('深拷贝: d = ', d)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d70ab544",
   "metadata": {},
   "source": [
    "## 25 python中的垃圾回收机制\n",
    "\n",
    "python GC主要使用**引用计数**（reference counting）来跟踪和回收垃圾。**标记-清除**（mark and sweep）解决容器对象可能产生的循环引用问题，通过**分代回收**(generation collection)，以空间换时间的方法提高垃圾回收效率。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eda935e8",
   "metadata": {},
   "source": [
    "## 26 python的List\n",
    "\n",
    "[python中list的实现](https://www.jianshu.com/p/J4U6rR)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c22fbafc",
   "metadata": {},
   "source": [
    "## 27 python中的is\n",
    "\n",
    "1) \"is\"是一个**关键字**用于判断两个对象是否为同一个对象（比较内存地址）\n",
    "2) \"==\"则用来判断两个对象的值是否相同。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "6cfc0632",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "#### 2.1 比较is与“==”\n",
    "\n",
    "a = [1,2,3]\n",
    "b = a\n",
    "c = b\n",
    "d = [1,2,3]\n",
    "\n",
    "print(b is a)\n",
    "print(c is a) # 这里is判断用来判断“c”和“a”是否指向同一块内存地址（对象）\n",
    "print(d is a)\n",
    "\n",
    "print(d == a) # 判断两个对象地址的内容（值）是否相同。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4dc25053",
   "metadata": {},
   "source": [
    "## 28 read, readline 和 readlines\n",
    "\n",
    "- read 读取整个文件内容\n",
    "- readline 读取下一行，使用生成器方法\n",
    "- readlines 读取整个文件到一个迭代器，供用户进行遍历。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "e6c28794",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello,I am a student.\n",
      "what about you?\n",
      "Can you tell me?\n",
      "Here is my email:xxxxxxxxx\n",
      "And how can we human studying python work and life?\n",
      "I think if life is a poem and I must be a poet\n",
      "\n",
      "omga, this file is a test that I used to study file exercise\n",
      "OK,that's OK\n",
      "END\n",
      "========================================================\n",
      "hello,I am a student.\n",
      "what about you?\n",
      "Can you tell me?\n",
      "Here is my email:xxxxxxxxx\n",
      "And how can we human studying python work and life?\n",
      "I think if life is a poem and I must be a poet\n",
      "\n",
      "omga, this file is a test that I used to study file exercise\n",
      "OK,that's OK\n",
      "END\n",
      "========================================================\n",
      "<class 'list'>\n",
      "hello,I am a student.\n",
      "what about you?\n",
      "Can you tell me?\n",
      "Here is my email:xxxxxxxxx\n",
      "And how can we human studying python work and life?\n",
      "I think if life is a poem and I must be a poet\n",
      "\n",
      "omga, this file is a test that I used to study file exercise\n",
      "OK,that's OK\n",
      "END\n"
     ]
    }
   ],
   "source": [
    "END_STRING = '========================================================'  #在两个不同的输出结果中间打印分隔符\n",
    "\n",
    "file_path = \"./basic problem/test.text\"\n",
    "with open(file_path,'r') as f:\n",
    "    content = f.read()              #read()\n",
    "    print(content)\n",
    "\n",
    "print(END_STRING)\n",
    "\n",
    "with open(file_path,'r') as f:\n",
    "    fline = f.readline()            #readline()\n",
    "    while fline:\n",
    "        print(fline.strip())  ##如果写为fline,那么每一行结束后都会打印出一个换行符。\n",
    "        fline = f.readline()\n",
    "\n",
    "print(END_STRING)\n",
    "\n",
    "with open(file_path,'r') as f:\n",
    "    lines = f.readlines()\n",
    "    print(type(lines))\n",
    "    for line in lines:\n",
    "        print(line.strip())  ## 每一行输出之间相隔两行？挺奇怪的"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c0c2f40",
   "metadata": {},
   "source": [
    "## 29 python2 和 python3的区别\n",
    "\n",
    "[思否社区](https://segmentfault.com/a/1190000015700980)\n",
    "\n",
    "主要区别点在于：\n",
    "1. print函数\n",
    "2. Unicode编码\n",
    "3. 除法运算\n",
    "4. 异常\n",
    "5. xrange\n",
    "6. 数据类型\n",
    "7. 文件"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b41b57a",
   "metadata": {},
   "source": [
    "## 30 super init\n",
    "[stack overflow](https://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods)\n",
    "[python文档](https://docs.python.org/2/library/functions.html#super)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "697e2fe4",
   "metadata": {},
   "source": [
    "## 31 range 和 xrange\n",
    "\n",
    "range创建一个列表，因此当用户执行range(1, 100),程序会在内存中创建一个包含99个元素的列表。\n",
    "\n",
    "xrange是一个延迟计算的序列对象\n",
    "\n",
    "但是：在python3中，range相当于python2里面的xrange，而xrange已经不复存在。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "env_py38",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
